
package com.hlkj.pay.app.merchant.ext.impl.lakala.handler;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantAccessContext;
import com.hlkj.pay.app.merchant.ext.impl.MerchantAccessCommonUtil;
import com.hlkj.pay.app.merchant.ext.impl.MerchantAccessUploadFile;
import com.hlkj.pay.app.merchant.ext.impl.lakala.dto.LakalaConfig;
import com.hlkj.pay.app.merchant.ext.impl.lakala.dto.resp.LakalaFileRes;
import com.hlkj.pay.common.MerchantResultCode;
import com.hlkj.pay.dto.common.LocationDto;
import com.hlkj.pay.dto.merchant.MerchantAccessDto;
import com.hlkj.pay.dto.merchant.ProviderChannelFeeConfigList;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.merchant.*;
import com.hlkj.pay.infrastructure.model.pay.PayChannelDictDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelRequestDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.util.FileUtils;
import com.hlkj.pay.util.ImageUtils;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.StringPool;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 汇付 商户进件参数处理
 * 
 * @author HlpayTeam
 * @date 2024/09/26 12:02
 */
@Slf4j
@Service
public class LakalaMerchantParamsHandle extends LakalaMerchantCommonParamsHandle {

    @Autowired
    private OkHttpClient okHttpClient;

    /**
     * 企业商户进件-新增参数组装
     *
     * @param channelMerchantAccessContext
     * @return
     */
    public CommonResult<Void> merchantApplyParamsCheck(ChannelMerchantAccessContext channelMerchantAccessContext) {
        MerchantAccessDto merchantAccessDto = channelMerchantAccessContext.getMerchantAccessDto();
        MerchantAccessBusinessDO merchantAccessBusiness = merchantAccessDto.getMerchantAccessBusiness();
        MerchantAccessInfoDO merchantAccessInfo = merchantAccessDto.getMerchantAccessInfo();
        String name = merchantAccessBusiness.getShortName();
        String shortName = merchantAccessInfo.getName();
        // shortName 为注册名称
        // name 为经营名称
        if (name.length() > 20 || name.length() < 4) {
            return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getCode(),
                 MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getMsg() + "拉卡拉仅商户注册名称必须四至二十个中文字符");
        }
//        if (shortName.length() < 7) {
//            return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getCode(), MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getMsg() + "拉卡拉仅经营名称不能少于7个中文字符");
//        }

        switch (MerchantEnum.MERCHANT_TYPE.from(merchantAccessInfo.getType())) {
            case PERSONAL:
                if (!StringUtils.hasText(merchantAccessBusiness.getBusinessDesc())) {
                    return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getCode(),
                            MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getMsg() + "拉卡拉个人业务描述不能为空");
                }
                break;
            default:
        }
        List<ProviderChannelFeeConfigList> merchantFeeConfigList = channelMerchantAccessContext.getMerchantFeeConfigList();
        Map<Integer, List<ProviderChannelFeeConfigList>> merchantFeeConfigMap = merchantFeeConfigList.stream()
                .collect(Collectors.groupingBy(merchantFeeConfig -> merchantFeeConfig.getPayWayDO().getType()));

        for (Map.Entry<Integer, List<ProviderChannelFeeConfigList>> entry : merchantFeeConfigMap.entrySet()) {
            List<ProviderChannelFeeConfigList> value = entry.getValue();
            PayWayDO payWayDO = value.get(0).getPayWayDO();
            ProviderChannelFeeConfigList providerChannelFeeConfigList = MerchantAccessCommonUtil.defaultFeeConfig(value);
            if (providerChannelFeeConfigList != null) {
                switch (PayEnums.PAY_TYPE.fromByCode(payWayDO.getType())) {
                    case UNION_APY:
                        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(providerChannelFeeConfigList.getSeniorFeeType())
                                || providerChannelFeeConfigList.getSeniorFeeConfigValue() == null
                                || providerChannelFeeConfigList.getSeniorFeeConfigValue().getProviderMaxFee() == null) {
                            return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getCode(),
                                    MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getMsg() + "拉卡拉银联支付方式,必须配置封顶值");
                        }
                    default:
                }
            }
        }
        return CommonResult.success();
    }

    /**
     * 企业商户进件-新增参数组装
     *
     * @param channelMerchantAccessContext
     * @return
     */
    public Map<String, Object> merchantApplyParams(ChannelMerchantAccessContext channelMerchantAccessContext, LakalaConfig lakalaConfig) {
        Map<String, Object> params = new HashMap<>();
        MerchantAccessDto merchantAccessDto = channelMerchantAccessContext.getMerchantAccessDto();
        MerchantAccessBusinessDO merchantAccessBusiness = merchantAccessDto.getMerchantAccessBusiness();
        MerchantAccessInfoDO merchantAccessInfo = merchantAccessDto.getMerchantAccessInfo();
        MerchantAccessCertInfoDO merchantAccessLegal = merchantAccessDto.getMerchantAccessLegal();
        MerchantAccessCertInfoDO merchantAccessContact = merchantAccessDto.getMerchantAccessContact();
        MerchantAccessCardDO merchantAccessCard = merchantAccessDto.getMerchantAccessCard();
        ProviderChannelConfigDO providerChannelConfigDO = channelMerchantAccessContext.getProviderChannelConfig();
        List<ProviderChannelFeeConfigList> merchantFeeConfigList = channelMerchantAccessContext.getMerchantFeeConfigList();

        params.put("userNo", lakalaConfig.getUserNo());
        params.put("email", merchantAccessContact.getOtherValue());
        // 先进件B2B_SYT 收银台就行，后续在进行增终，专业化扫码
        params.put("busiCode", "B2B_SYT");
        params.put("merRegName", merchantAccessBusiness.getShortName());

        switch (MerchantEnum.MERCHANT_TYPE.from(merchantAccessInfo.getType())) {
            case PERSONAL:
                params.put("merType", "TP_PERSONAL");
                params.put("businessContent", merchantAccessBusiness.getBusinessDesc());
                break;
            default:
                MerchantAccessLicenseDO merchantAccessLicense = merchantAccessDto.getMerchantAccessLicense();
                params.put("merType", "TP_MERCHANT");
                params.put("licenseName", merchantAccessLicense.getName());
                params.put("licenseNo", merchantAccessLicense.getLicenseCode());
                params.put("licenseDtStart", date(merchantAccessLicense.getLicenseBeginDate()));
                params.put("licenseDtEnd", date(merchantAccessLicense.getLicenseEndDate()));
                params.put("businessContent", merchantAccessLicense.getBusinessScope());
        }
        params.put("merName", merchantAccessBusiness.getShortName());
        params.put("merAddr", merchantAccessBusiness.getAddress());
        params.put("provinceCode", merchantAccessBusiness.getProvinceCode());
        params.put("cityCode", merchantAccessBusiness.getCityCode());
        params.put("countyCode", merchantAccessBusiness.getAreaCode());
        LocationDto locationDto = channelMerchantAccessContext.getLocationDto();
        params.put("latitude", locationDto.getLatitude());
        params.put("longtude", locationDto.getLongitude());
        params.put("source", "H5");

        params.put("larName", merchantAccessLegal.getName());
        params.put("larIdType", certType(merchantAccessLegal.getCertType()));
        params.put("larIdCard", merchantAccessLegal.getCertNo());
        params.put("larIdCardStart", date(merchantAccessLegal.getCertBeginDate()));
        params.put("larIdCardEnd", date(merchantAccessLegal.getCertEndDate()));

        params.put("contactMobile", merchantAccessContact.getPhone());
        params.put("contactName", merchantAccessContact.getName());
        switch (MerchantEnum.CARD_TYPE.from(merchantAccessCard.getType())) {
            case CORPORATE_ACCOUNT:
                params.put("accountType", "57");
                params.put("accountIdType", certType(merchantAccessCard.getCertType()));
                params.put("accountIdCard", merchantAccessCard.getCertNo());
                params.put("accountIdDtStart", date(merchantAccessCard.getCertBeginDate()));
                params.put("accountIdDtEnd", date(merchantAccessCard.getCertEndDate()));
                break;
            default:
                params.put("accountType", "58");
                params.put("accountIdType", certType(merchantAccessCard.getCertType()));
                params.put("accountIdCard", merchantAccessCard.getCertNo());
                params.put("accountIdDtStart", date(merchantAccessCard.getCertBeginDate()));
                params.put("accountIdDtEnd", date(merchantAccessCard.getCertEndDate()));
        }
        params.put("openningBankCode", merchantAccessCard.getBankCode());
        params.put("openningBankName", merchantAccessCard.getBankName());
        params.put("clearingBankCode", merchantAccessCard.getBranchCode());
        params.put("accountNo", merchantAccessCard.getCardNo());
        params.put("accountName", merchantAccessCard.getName());

        ProviderChannelFeeConfigList settleCycleConf = getSettleCycle(merchantFeeConfigList);

        if (MerchantEnum.SETTLE_CYCLE.D0.getPayWayCode().equals(settleCycleConf.getPayWayDO().getCode())) {
            params.put("settleType", "D0");
        } else if (MerchantEnum.SETTLE_CYCLE.D1.getPayWayCode().equals(settleCycleConf.getPayWayDO().getCode())) {
            params.put("settleType", "D1");
        }
        Map<String, String> result = channelMerchantAccessContext.getPayChannelDictList().stream()
                .collect(Collectors.toMap(PayChannelDictDO::getDictValue, PayChannelDictDO::getDictDesc));

        params.put("settleProvinceCode", merchantAccessCard.getProvinceCode());
        params.put("settleProvinceName", result.get(merchantAccessCard.getProvinceCode()));
        params.put("settleCityCode", merchantAccessCard.getCityCode());
        params.put("settleCityName", result.get(merchantAccessCard.getCityCode()));
        params.put("settlementType", "AUTOMATIC");
        Map<String, Object> bizContent = new HashMap<>();
        bizContent.put("termNum", 1);
        bizContent.put("mcc", merchantAccessBusiness.getMcc());
        bizContent.put("activityId", lakalaConfig.getActivityId());
        List<Map<String, Object>> fees = new ArrayList<>();
        Map<Integer, List<ProviderChannelFeeConfigList>> merchantFeeConfigMap = merchantFeeConfigList.stream()
                .collect(Collectors.groupingBy(merchantFeeConfig -> (merchantFeeConfig.getPayWayDO().getType())));
        merchantFeeConfigMap.forEach((key, value) -> {
            PayWayDO payWayDO = value.get(0).getPayWayDO();
            Map<String, Object> fee = new HashMap<>();
            switch (PayEnums.PAY_TYPE.fromByCode(payWayDO.getType())) {
                case WECHAT:
                    Map<Integer, List<ProviderChannelFeeConfigList>> sceneFeeConfigMap = value.stream()
                            .collect(Collectors.groupingBy(merchantFeeConfig -> (merchantFeeConfig.getPayWayDO().getSceneType())));
                    List<ProviderChannelFeeConfigList> onlineFeeConfigLists = sceneFeeConfigMap.get(PayEnums.SCENE_TYPE.ONLINE.getCode());
                    List<ProviderChannelFeeConfigList> offlineFeeConfigLists = sceneFeeConfigMap.get(PayEnums.SCENE_TYPE.OFFLINE.getCode());
                    if (!CollectionUtils.isEmpty(onlineFeeConfigLists)) {
                        ProviderChannelFeeConfigList providerChannelFeeConfigList = MerchantAccessCommonUtil.defaultFeeConfig(onlineFeeConfigLists);
                        fee.put("feeCode", "LINE_WECHAT");
                        fee.put("feeValue", providerChannelFeeConfigList.getDefaultFeeConfigValue().getRateBase());
                        fees.add(fee);
                    }
                    if (!CollectionUtils.isEmpty(offlineFeeConfigLists)) {
                        ProviderChannelFeeConfigList providerChannelFeeConfigList = MerchantAccessCommonUtil.defaultFeeConfig(offlineFeeConfigLists);
                        fee.put("feeCode", "WECHAT");
                        fee.put("feeValue", providerChannelFeeConfigList.getDefaultFeeConfigValue().getRateBase());
                        fees.add(fee);
                    }
                    break;
                case ALIPAY:
                    ProviderChannelFeeConfigList alipayFeeConfigList = MerchantAccessCommonUtil.defaultFeeConfig(value);
                    fee.put("feeCode", "ALIPAY");
                    fee.put("feeValue", alipayFeeConfigList.getDefaultFeeConfigValue().getRateBase());
                    fees.add(fee);
                    break;
                case UNION_APY:
                    ProviderChannelFeeConfigList unionFeeConfigList = MerchantAccessCommonUtil.defaultFeeConfig(value);
                    fee.put("feeCode", "UNIONPAY_WALLET_DEBIT_FEE");
                    fee.put("topFee", unionFeeConfigList.getSeniorFeeConfigValue().getProviderMaxFee());
                    fee.put("feeValue", unionFeeConfigList.getDefaultFeeConfigValue().getRateBase());
                    fees.add(fee);
                    break;
                case FUNCTION:
                    Map<String, ProviderChannelFeeConfigList> functionFeeMap = value.stream()
                            .collect(Collectors.toMap(providerChannelFeeConfigList -> providerChannelFeeConfigList.getPayWayCode(), Function.identity()));
                    if (functionFeeMap.keySet().contains(MerchantEnum.SETTLE_CYCLE.D0.getPayWayCode())) {
                        ProviderChannelFeeConfigList d0FeeConfigList = functionFeeMap.get(functionFeeMap.get(MerchantEnum.SETTLE_CYCLE.D0.getPayWayCode()));
                        if (CommonEnum.YES_NO_TYPE.YES.getCode().equals(d0FeeConfigList.getStatus())) {
                            fee.put("feeCode", "MER_WITHDRAWAL_SECOND");
                            fee.put("feeValue", d0FeeConfigList.getDefaultFeeConfigValue().getRateBase());
                            fees.add(fee);
                            fee.put("feeCode", "SCAN_PAY_SECOND");
                            fee.put("feeValue", d0FeeConfigList.getDefaultFeeConfigValue().getRateBase());
                            fees.add(fee);
                            fee.put("feeCode", "CARD_SECOND");
                            fee.put("feeValue", d0FeeConfigList.getDefaultFeeConfigValue().getRateBase());
                            fees.add(fee);
                        }
                    }
                    break;
                default:
                    return;
            }
        });

        Map<String, Object> CREDIT_CARD = new HashMap<>();
        CREDIT_CARD.put("feeCode", "CREDIT_CARD");
        CREDIT_CARD.put("feeValue", "0.6");

        Map<String, Object> DEBIT_CARD = new HashMap<>();
        DEBIT_CARD.put("feeCode", "CREDIT_CARD");
        DEBIT_CARD.put("feeValue", "0.6");
        DEBIT_CARD.put("topFee", "25");

        fees.add(CREDIT_CARD);
        bizContent.put("fees", fees);
        params.put("bizContent", bizContent);
        params.put("settlementType", "AUTOMATIC");
        params.put("attchments", fileList(channelMerchantAccessContext.getMerchantAccessUploadFiles()));
        return params;

    }

    private static ProviderChannelFeeConfigList getSettleCycle(List<ProviderChannelFeeConfigList> merchantFeeConfigList) {
        return merchantFeeConfigList.stream().filter(conf -> Objects.equals(conf.getPayWayDO().getType(), PayEnums.PAY_TYPE.FUNCTION.getCode())).findFirst().get();
    }

    /**
     * 新增文件参数转换
     *
     * @param channelMerchantAccessContext
     */
    public void addProcessFileId(ChannelMerchantAccessContext channelMerchantAccessContext, LakalaConfig lakalaConfig) {
        MerchantAccessLicenseDO merchantAccessLicense = channelMerchantAccessContext.getMerchantAccessDto().getMerchantAccessLicense();
        MerchantAccessCertInfoDO merchantAccessCert = channelMerchantAccessContext.getMerchantAccessDto().getMerchantAccessLegal();
        MerchantAccessCardDO merchantAccessCard = channelMerchantAccessContext.getMerchantAccessDto().getMerchantAccessCard();
        PayChannelRequestDO beforeMerchantAccessRequestDO = channelMerchantAccessContext.getBeforePayChannelRequestDO();
        MerchantAccessBusinessDO merchantAccessBusiness = channelMerchantAccessContext.getMerchantAccessDto().getMerchantAccessBusiness();
        MerchantAccessInfoDO merchantAccessInfo = channelMerchantAccessContext.getMerchantAccessDto().getMerchantAccessInfo();
        // 配置转换
        boolean test = channelMerchantAccessContext.isTest();
        Map<String, String> fileMap = new HashMap<>();
        if (beforeMerchantAccessRequestDO != null && StringUtils.hasText(beforeMerchantAccessRequestDO.getFileParams())) {
            fileMap = JsonUtils.parseObject(beforeMerchantAccessRequestDO.getFileParams(), Map.class);
        }
        try {
            // ID_CARD_FRONT 身份证正⾯
            // ID_CARD_BEHIND 身份证反⾯
            // BUSINESS_LICENCE 营业执照照⽚
            // BANK_CARD 银行卡（企业对公不需要传）
            // AGREE_MENT 协议
            // OPENING_PERMIT 开户许可证（企业对公需要传）
            // CHECKSTAND_IMG 收银台照片(必传)
            // SHOP_OUTSIDE_IMG 上传门头照片(必传)
            // SHOP_INSIDE_IMG 商铺内部照片(必传)
            // OTHERS 其他 无对应类型图片，请传其他类型
            // SETTLE_ID_CARD_FRONT 结算人身份证人像面
            // SETTLE_ID_CARD_BEHIND 结算人身份证国徽面
            // LETTER_OF_AUTHORIZATION 法人授权涵
            List<MerchantAccessUploadFile> merchantAccessUploadFiles = new ArrayList<>();

            //企业才有营业执照
            if (Objects.equals(MerchantEnum.MERCHANT_TYPE.COMPANY.getCode(), merchantAccessInfo.getType())) {
                merchantAccessUploadFiles
                        .add(MerchantAccessUploadFile.builder().fileKey("BUSINESS_LICENCE").fileUrl(merchantAccessLicense.getLicenseUrl()).fieldName("licensePicFileId").build());
            }
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("ID_CARD_FRONT").fileUrl(merchantAccessCert.getCertFrontUrl()).fieldName("legalCertFrontFileId").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("ID_CARD_BEHIND").fileUrl(merchantAccessCert.getCertBackUrl()).fieldName("legalCertBackFileId").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("OPENING_PERMIT").fileUrl(merchantAccessCard.getLicenseUrl()).fieldName("regAcctFileId").build());
            //
            List<String> fileUrls = merchantAccessBusiness.getFileUrls();
            if (!CollectionUtils.isEmpty(fileUrls)) {
                merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("AGREE_MENT").fileUrl(fileUrls.get(0)).fieldName("regAcctFileId").build());
            }
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("BANK_CARD").fileUrl(merchantAccessCard.getSettleCardFrontUrl()).fieldName("settleCardFrontFileId").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("SETTLE_ID_CARD_FRONT").fileUrl(merchantAccessCard.getCertFrontUrl())
                    .fieldName("settleCertFrontFileId").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("SETTLE_ID_CARD_BEHIND").fileUrl(merchantAccessCard.getCertBackUrl())
                    .fieldName("settleCertBackFileId").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("LETTER_OF_AUTHORIZATION").fileUrl(merchantAccessCard.getAuthUrl()).fieldName("authEnturstFileId").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("SHOP_OUTSIDE_IMG").fileUrl(merchantAccessBusiness.getStoreHeaderUrl()).fieldName("storeHeaderFileId").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("CHECKSTAND_IMG").fileUrl(merchantAccessBusiness.getStoreCashierDeskUrl())
                    .fieldName("storeCashierDeskFileId").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("SHOP_INSIDE_IMG").fileUrl(merchantAccessBusiness.getStoreIndoorUrl()).fieldName("storeIndoorFileId").build());
            for (MerchantAccessUploadFile merchantAccessUploadFile : merchantAccessUploadFiles) {
                CommonResult<Void> f07 = fileUploadProcess(fileMap, lakalaConfig, merchantAccessUploadFile, test);
                if (!f07.isSuccess()) {
                    channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
                    channelMerchantAccessContext.setRemark(f07.getMsg());
                    return;
                }
            }
            // 转换 List<MerchantAccessUploadFile> 为 Map<String, String>
            // Map<String, String> result =
            // merchantAccessUploadFiles.stream().filter(merchantAccessUploadFile ->
            // StringUtils.hasText(merchantAccessUploadFile.getFileId()))
            // .collect(Collectors.toMap(MerchantAccessUploadFile::getFieldName,
            // MerchantAccessUploadFile::getFileId));
            // channelMerchantAccessContext.setMerchantAccessFile(BeanUtils.mapToBean(result,
            // MerchantAccessFile.class));
            channelMerchantAccessContext.setMerchantAccessUploadFiles(merchantAccessUploadFiles);
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        finally {
            PayChannelRequestDO payChannelRequestDO = channelMerchantAccessContext.getPayChannelRequestDO();
            if (payChannelRequestDO == null) {
                payChannelRequestDO = new PayChannelRequestDO();
            }
            payChannelRequestDO.setFileParams(JsonUtils.toJsonString(fileMap));
            channelMerchantAccessContext.setPayChannelRequestDO(payChannelRequestDO);
        }
    }

    public CommonResult<Void> fileUploadProcess(Map<String, String> fileMap, LakalaConfig lakalaConfig, MerchantAccessUploadFile merchantAccessUploadFile, boolean test) {
        if (!StringUtils.hasText(merchantAccessUploadFile.getFileUrl())) {
            return CommonResult.success();
        }
        String fileKey = merchantAccessUploadFile.getFileUrl().hashCode() + "_" + merchantAccessUploadFile.getFileKey();
        String fileId = fileMap.get(fileKey);
        if (StringUtils.hasText(fileId)) {
            log.info("拉卡拉文件映射获取成功 fileUrl:{},fileId:{}", merchantAccessUploadFile.getFileUrl(), fileId);
            merchantAccessUploadFile.setFileId(fileId);
            return CommonResult.success();
        }
        log.info("拉卡拉文件映射获取未成功 fileType:{}, fileUrl:{}", test, merchantAccessUploadFile.getFileUrl());
        CommonResult<Void> f371 = fileUpload(merchantAccessUploadFile, lakalaConfig, test);
        if (f371.isSuccess()) {
            fileMap.put(fileKey, merchantAccessUploadFile.getFileId());
        }
        return f371;
    }

    /**
     * 文件上传
     *
     * @param merchantAccessUploadFile
     * @param lakalaConfig
     * @return
     * @throws Exception
     */
    public CommonResult<Void> fileUploadNew(MerchantAccessUploadFile merchantAccessUploadFile, LakalaConfig lakalaConfig, boolean test) {
        if (!file(merchantAccessUploadFile.getFileUrl())) {
            log.info("文件格式错误 跳过文件上传:fileUrl:{},test:{}", merchantAccessUploadFile.getFileUrl(), test);
            return CommonResult.success();
        }
        File tempFile = null;
        try {
            tempFile = File.createTempFile("temp", ".tmp");
            URL url = new URL(merchantAccessUploadFile.getFileUrl());
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            // File file = new File(connection.getInputStream());
            // 创建临时文件
            // 将输入流复制到临时文件中
            try (OutputStream outputStream = new FileOutputStream(tempFile)) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = connection.getInputStream().read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }

            String contentType = "image/" + ImageUtils.getImageTypeFromUrl(merchantAccessUploadFile.getFileUrl());
            String imageName = ImageUtils.getImageNameFromUrl(merchantAccessUploadFile.getFileUrl());
            // 使用文件字节流构造 RequestBody 来上传
            // MediaType mediaType = MediaType.parse(contentType); // 根据文件类型设置
            MediaType mediaType = MediaType.parse("multipart/form-data; boundary=------------------------7e22d00dba620c19");
            RequestBody requestBody = RequestBody.create(mediaType, tempFile);

            // 创建 MultipartBody 来上传文件，并添加自定义 Header
            MultipartBody multipartBody = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("file", imageName, requestBody)
                    .addFormDataPart("imgType", merchantAccessUploadFile.getFileKey())// 文件的表单字段
                    .addFormDataPart("sourcechnl", "PC")// 文件的表单字段
                    .addFormDataPart("isOcr", String.valueOf(false))// 文件的表单字段
                    .build();
            CommonResult<String> token = token(lakalaConfig, test);

            // 创建上传请求，并设置自定义 Header
            Request uploadRequest = new Request.Builder().url(fileUrl(test) + "/file/upload").header("Authorization", "Bearer " + token.getData())
                    // .header("Content-Type", "multipart/form-data;") // 上传时的授权头
                    .post(multipartBody).build();

            // 发送上传请求
            try (Response uploadResponse = okHttpClient.newCall(uploadRequest).execute()) {
                String body = uploadResponse.body().string();
                log.info("拉卡拉文件上传返回:{}", body);
                if (uploadResponse.isSuccessful()) {
                    LakalaFileRes lakalaFileRes = JsonUtils.parseObject(body, LakalaFileRes.class);
                    merchantAccessUploadFile.setFileId(lakalaFileRes.getUrl());
                    return CommonResult.success();
                }
                else {
                    return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_FILE_ERROR.getCode(), body);
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
            log.error("拉卡拉图片上传失败:{}", e.getMessage());
            return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_FILE_ERROR.getCode(), e.getMessage());
        }
    }

    /**
     * 文件上传
     *
     * @param merchantAccessUploadFile
     * @param lakalaConfig
     * @return
     * @throws Exception
     */
    public CommonResult<Void> fileUpload(MerchantAccessUploadFile merchantAccessUploadFile, LakalaConfig lakalaConfig, boolean test) {
        if (!file(merchantAccessUploadFile.getFileUrl())) {
            log.info("文件格式错误 跳过文件上传:fileUrl:{},test:{}", merchantAccessUploadFile.getFileUrl(), test);
            return CommonResult.success();
        }
        try {
            byte[] fileBytes = FileUtils.fileBytes(merchantAccessUploadFile.getFileUrl()); // 获取文件字节流
            String contentType = "image/" + ImageUtils.getImageTypeFromUrl(merchantAccessUploadFile.getFileUrl());
            String imageName = ImageUtils.getImageNameFromUrl(merchantAccessUploadFile.getFileUrl());
            // 使用文件字节流构造 RequestBody 来上传
            // MediaType mediaType = MediaType.parse(contentType); // 根据文件类型设置
            MediaType mediaType = MediaType.parse("multipart/form-data"); // 根据文件类型设置
            RequestBody requestBody = RequestBody.create(mediaType, fileBytes);

            // 创建 MultipartBody 来上传文件，并添加自定义 Header
            MultipartBody multipartBody = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("file", imageName, requestBody)
                    .addFormDataPart("imgType", merchantAccessUploadFile.getFileKey())// 文件的表单字段
                    .addFormDataPart("sourcechnl", "PC")// 文件的表单字段
                    .addFormDataPart("isOcr", String.valueOf(false))// 文件的表单字段
                    .build();
            CommonResult<String> token = token(lakalaConfig, test);

            // 创建上传请求，并设置自定义 Header
            Request uploadRequest = new Request.Builder().url(fileUrl(test) + "/file/upload").header("Authorization", "Bearer " + token.getData())
                    // .header("Content-Type", "multipart/form-data;") // 上传时的授权头
                    .post(multipartBody).build();

            // 发送上传请求
            try (Response uploadResponse = okHttpClient.newCall(uploadRequest).execute()) {
                String body = uploadResponse.body().string();
                log.info("拉卡拉文件上传返回:{}", body);
                if (uploadResponse.isSuccessful()) {
                    LakalaFileRes lakalaFileRes = JsonUtils.parseObject(body, LakalaFileRes.class);
                    merchantAccessUploadFile.setFileId(lakalaFileRes.getUrl());
                    return CommonResult.success();
                }
                else {
                    return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_FILE_ERROR.getCode(), uploadResponse.message());
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
            log.error("拉卡拉图片上传失败:{}", e.getMessage());
            return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_FILE_ERROR.getCode(), e.getMessage());
        }
    }

    public static boolean file(String fileUrl) {
        if (!StringUtils.hasText(fileUrl)) {
            return false;
        }
        int indexOf = fileUrl.lastIndexOf(StringPool.SLASH);
        if (indexOf < 0) {
            return false;
        }
        String fileType = fileUrl.substring(indexOf);
        if (!fileType.contains(StringPool.DOT)) {
            return false;
        }
        return true;
    }



    List<Map<String, Object>> fileList(List<MerchantAccessUploadFile> merchantAccessUploadFiles) {
        List<Map<String, Object>> fileMapList = new ArrayList<>();
        merchantAccessUploadFiles.stream().forEach(merchantAccessUploadFile -> {
            if (StringUtils.hasText(merchantAccessUploadFile.getFileId())) {
                fileMapList.add(fileMap(merchantAccessUploadFile.getFileId(), merchantAccessUploadFile.getFileKey()));
            }
        });
        return fileMapList;
    }

    Map<String, Object> fileMap(String fileId, String type) {
        Map<String, Object> fileMap = new HashMap<>();
        fileMap.put("id", fileId);
        fileMap.put("type", type);
        return fileMap;
    }

}
